package com.atguigu.gmall.common.config.pool;

import com.atguigu.gmall.common.config.pool.properties.AppThreadPoolProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author nicc
 * @version 1.0
 * @className AppThreadPoolConfiguration
 * @date 2022-10-13 01:55
 */
//1、开启 AppThreadPoolProperties 的属性配置绑定
//2、把 AppThreadPoolProperties 放到容器中
@EnableConfigurationProperties(AppThreadPoolProperties.class)
@Configuration
public class AppThreadPoolConfiguration {

    /**
     * int corePoolSize,        核心大小
     * int maximumPoolSize,     最大大小(额外开的线程数【kat时间不用就销毁】 = 最大 - 核心)
     * long keepAliveTime,      线程空闲时间
     * TimeUnit unit,           时间单位
     * BlockingQueue<Runnable> workQueue,   排队队列
     * ThreadFactory threadFactory,         线程工厂
     * RejectedExecutionHandler handler     拒绝策略
     * @return
     *
     * 如果线程数量已经达到最大，而且队列满了。新任务再进来，利用拒绝策略进行拒绝；
     * 线上提交的任务都是要被执行的，如果线程池没满，就用线程池启动一个异步线程执行（用户感觉快）。
     * 如果线程池满了，让提交任务的当前线程，自己同步运行这个任务即可（用户感觉慢一点）。
     *
     * @Bean标注的方法。如果有任何参数。这些参数默认都去容器中获取组件
     */
    @Primary//当配置类中声明多个同类型组件，用该注解来表示主要的
    @Bean
    public ThreadPoolExecutor threadPoolExecutor(AppThreadPoolProperties threadPoolProperties,
                                                 @Value("${spring.application.name}") String applicationName){
        //1、线程池想要对接监控平台。
        //2、监控平台自己从redis中拉取各种指标，进行可视化展示

        return new ThreadPoolExecutor(
                threadPoolProperties.getCorePoolSize(),
                threadPoolProperties.getMaximumPoolSize(),
                threadPoolProperties.getKeepAliveTime(),
                TimeUnit.MINUTES,
                new LinkedBlockingQueue<>(threadPoolProperties.getWorkQueueSize()),
                new ThreadFactory() { // 线程池中所有线程都是线程工厂new的
                    int i = 0; //单线程
                    @Override
                    public Thread newThread(Runnable r) {
                        //分布于全线程数量限制  redis.incr(thread-count) < 10000

                        //利用层层封装嵌套可以实现所有完整功能
//                        Runnable runnable = new Runnable() {
//                            @Override
//                            public void run() { //根据cpu调度执行
//
//                            }
//                        };

                        Thread thread = new Thread(() -> {
                            //redis.incr("running...") 任务前置逻辑增强
                            r.run();//真实任务
                            //redis.decr("running...") 任务后置逻辑增强
                        });
                        thread.setName("【"+ applicationName +"】-apppool-" + (i++));
                        //thread.setPriority(); 设置优先级
                        return thread;
                    }
                },
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }


    /**
     * 线上应用突然内存不足，疯狂gc？
     * - 手动降级：关闭副线程池
     * - 熔断(系统保护机制)、降级（手动保护机制）： 效果：都不能继续使用服务。
     * @param threadPoolProperties
     * @param applicationName
     * @return
     */
//    @Bean
//    public ThreadPoolExecutor
//      otherPool(AppThreadPoolProperties threadPoolProperties,
//             @Value("${spring.application.name}") String applicationName){
//        //1、线程池想要对接监控平台。
//        //2、监控平台自己从redis中拉取各种指标，进行可视化展示
//        //3、
//        return new ThreadPoolExecutor(threadPoolProperties.getCorePoolSize(),
//                threadPoolProperties.getMaximumPoolSize(),
//                threadPoolProperties.getKeepAliveTime(),
//                TimeUnit.MILLISECONDS,
//                new LinkedBlockingQueue<>(threadPoolProperties.getWorkQueueSize()),
//                new ThreadFactory() { //线程池中所有的线程都是它new的
//                    int i = 0; //单线程
//                    @Override
//                    public Thread newThread(Runnable r) {
//                        // 分布式全线程数量限制：redis.incr(thread-count) < 100000
//
//                        //利用层层封装完整所有功能
////                        Runnable runnable = new Runnable() {
////                            @Override
////                            public void run() { //根据cpu调度
////
////                            }
////                        };
//                        Thread thread = new Thread(()->{
//                            //redis.incr("running...") 任务前置逻辑增强
//                            r.run(); //跑真实任务
//                            //redis.decr("running...") 任务后置逻辑增强
//                        });
//                        thread.setName("【"+applicationName+"】-apppool-"+ (i++));
//                        return thread;
//                    }
//                },
//                new ThreadPoolExecutor.CallerRunsPolicy());
//    }

}
